function Scroller(){
    this.init$Eventable();
    this.initRenderable();
    this.$overScroll = true;
    this.$hScrollAlwaysVisible = false;
    this.$hScrollVisible = false;
    this.$width = 0;
    this.$height = 0;
    this.$lastClientWidth = -1;
    this.$lastClientHeight = -1;
    this.$scrollbarWidth = 0;
}
Scroller.prototype = {
    _TPL_ELM: '<div id="#{id}" style="position:relative;">' +
            '<div id="#{id}_scroller"  class="QEScroller" style="position:absolute;left:0;top:0;width:100%;height:100%;overflow-y:scroll;">' +
                '<div id="#{id}_scroll" class="QEScroll" style="cursor:text;"></div>' +
            '</div>' +
            '<div id="#{id}_content" onselectstart="return false;" style="position:absolute;left:0;top:0;cursor:text;overflow:hidden;"></div>' +
        '</div>',
    renderHTML: function (){
        return Utils.format(this._TPL_ELM, { id: this.id() });
    },
    postRender: function (){
        var elm = this.elm();
        var div = elm.ownerDocument.createElement('div');
        div.style.cssText = 'position:absolute;left:-32768px;width:200px;height:200px;overflow:scroll;';
        elm.appendChild(div);
        this.$scrollbarWidth = div.offsetWidth - div.clientWidth;
        DOMUtils.removeNode(div);
        var contentElm = this.contentElm();
        contentElm.style.width = this.getClientWidth() + 'px';
        contentElm.style.height = this.getClientHeight() + 'px';
        this.on(this.scrollerElm(), 'scroll', this._onScroll);
    },
    scrollerElm: function (){
        return this.elm('scroller');
    },
    scrollElm: function (){
        return this.elm('scroll');
    },
    contentElm: function (){
        return this.elm('content');
    },
    setOverScroll: function (value){
        this.$overScroll = value;
    },
    setHScrollAlwaysVisible: function (value){
        this.$hScrollAlwaysVisible = value;
    },
    setSize: function (size){
        this.$width = size[0];
        this.$height = size[1];
        this.elm().style.width = this.$width + 'px';
        this.elm().style.height = this.$height + 'px';
    },
    getClientWidth: function (){
        return Math.max(0, this.$width - this.$scrollbarWidth);
    },
    getClientHeight: function (){
        return Math.max(0, this.$height - (!this.$hScrollVisible ? 0 : this.$scrollbarWidth));
    },
    getContentWidth: function (){
        return this.$contentWidth;
    },
    getContentHeight: function (){
        return this.$contentHeight;
    },
    getScrollX: function (){
        return this.scrollerElm().scrollLeft;
    },
    getScrollY: function (){
        return this.scrollerElm().scrollTop;
    },
    setScrollX: function (x){
        this.scrollerElm().scrollLeft = x;
    },
    setScrollY: function (y){
        this.scrollerElm().scrollTop = y;
    },
    getClientSize: function (){
        return [this.getClientWidth(), this.getClientHeight()];
    },
    setContentSize: function (size){
        this.$contentWidth = size[0];
        if (this.$contentWidth < this.getClientWidth()) {
            this.$contentWidth = this.getClientWidth();
        }
        this._updateHScroll();
        this.$contentHeight = size[1];
        var scrollElm = this.scrollElm();
        if (this.$overScroll) {
            this.$contentHeight += this.getClientHeight();
        }
        scrollElm.style.width = this.$contentWidth + 'px';
        scrollElm.style.height = this.$contentHeight + 'px';
        this._update();
    },
    _update: function (){
        var clientWidth = this.getClientWidth();
        var clientHeight = this.getClientHeight();
        if (clientWidth !== this.$lastClientWidth || clientHeight !== this.$lastClientHeight) {
            this.$lastClientWidth = clientWidth;
            this.$lastClientHeight = clientHeight;
            this._onClientSizeChanged();
        }
    },
    _updateHScroll: function (){
        if (!this.$hScrollAlwaysVisible) {
            this.$hScrollVisible = this.$contentWidth >  this.getClientWidth();
            this.scrollerElm().style.overflowX = this.$hScrollVisible ? 'scroll' : 'hidden';
        }
    },
    _onScroll: function (){
        this.dispatchEvent({
            type: 'Scroll'
        });
    },
    _onClientSizeChanged: function (){
        var contentElm = this.contentElm();
        var width = this.getClientWidth();
        var height = this.getClientHeight();
        contentElm.style.width = width + 'px';
        contentElm.style.height = height + 'px';
        this.dispatchEvent({
            type: 'ClientSizeChanged',
            width: width,
            height: height
        });
    }
};

Utils.extend(Scroller, Eventable);
Utils.extend(Scroller, Renderable);
